package com.itheima.aspect;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Description: TimeAspect 运行时间切面类
 * @Author: HH
 * @Date: 2025/4/21 09:59
 **/
@Slf4j
@Aspect // 声明当前类为切面类
@Component // 将当前类注入到spring容器中, 方便自动注入管理
public class TimeAspect {

    @Autowired
    private HttpServletRequest request;

    /**
     * 切面方法
     * @Around 表示当前切面方法的通知类型为环绕通知(后续讲解) -> 环绕通知可以在目标方法执行前，后插入自定义逻辑，并且可以完全控制目标方法的执行流程（例如：是否执行、如何执行等）
     * execution(* com.itheima.service.impl.DeptServiceImpl.*(..)) 用于表示切入点表达式(用于定义哪些方法会被拦截)，与拦截器与过滤器类似
     * * 表示任意返回值
     * com.itheima.service.impl.DeptServiceImpl 表示一段指定的匹配规则路径
     * .*(..) 表示前面的路径下的所有方法(其中.. 表示方法可以接受任意数量和类型参数)
     * @param joinPoint ProceedingJoinPoint 是 Spring AOP 提供的一个接口，包含被拦截方法的相关信息(它提供了对目标方法的访问能力，包括方法签名、参数、返回值等信息)
     * @return 原始方法的返回值
     * @throws Throwable 如果原始方法抛出异常，则会传播给调用方 -> 默认处理异常方式为throw e(如果需要在切面中处理异常，可以通过捕获 Throwable 并执行自定义逻辑来实现)
     */
    @Around("execution(* com.itheima.service.impl.DeptServiceImpl.*(..))")
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        // 记录方法执行开始时间
        long start = System.currentTimeMillis();

        // 获取操作人的ip
        String ip = request.getLocalAddr();
        log.info("操作人IP: {}", ip);

        // 执行原始方法
        Object result = joinPoint.proceed(); // 仅使用Around 注解时, 需要手动调用原始方法

        // 记录方法执行结束时间
        long end = System.currentTimeMillis();

        // 计算方法执行耗时
        log.info("方法执行耗时: {}毫秒", end - start);
        return result;
    }
}
